# 作者: 家里蹲 吴越洋
# 2023年03月20日10时39分07秒
from socket import *
import struct
import os
from multiprocessing import Pool

class Server:
    def __init__(self,ip,port):
        self.server_socket:socket=None
        self.client_socket: socket = None
        self.ip=ip
        self.port=port
        self.path = os.getcwd()

    def tcp_init(self):
        server_socket=socket(AF_INET,SOCK_STREAM)
        # 重用对应地址和端口
        server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        server_socket.bind((self.ip,self.port))
        server_socket.listen(128)
        self.server_socket=server_socket

    def send_train(self,data,flag_bytes=False):
        if flag_bytes:
            data_len = len(data)
            self.client_socket.send(struct.pack('I', data_len))  # 发火车头，4个字节，包含的是文件名的长度
            self.client_socket.send(data)  # 车厢是文件名
        else:
            data_bytes=data.encode('utf8')
            data_len=len(data_bytes)
            # 发火车头
            self.client_socket.send(struct.pack('I',data_len))
            # 发信息
            self.client_socket.send(data_bytes)

    def recv_train(self,client_socket:socket):
        # 接受火车头
        train_len=client_socket.recv(4)
        # 解包获得长度
        train_content_len=struct.unpack('I',train_len)[0]
        # 接受内容
        train_content=client_socket.recv(train_content_len)
        return train_content.decode('utf8')


    def do_ls(self):
        """
        当前路径的信息传输给客户端
        :return:
        """
        data=''
        for file in os.listdir(self.path):
            data+=file+' '*5+str(os.stat(file).st_size)+'\n'
        self.send_train(data)

    def do_pwd(self):
        self.send_train(self.path+'\n')

    def do_cd(self,command):
        os.chdir(command[3:]) #改变路径
        self.path=os.getcwd()
        self.send_train(self.path+'\n')

    def do_gets(self, command):
        # 往客户端发送文件
        # 发文件名
        file_name=command[5:] #认为文件名一定存在
        self.send_train(file_name)
        # 发文件内容
        file=open(file_name,'rb')
        data=file.read()
        self.send_train(data,True)
        file.close()

    def do_puts(self,command):
        # 从客户端接受文件
        file_name=command[5:]
        file=open(file_name,'wb')
        train_len=self.client_socket.recv(4)
        content_len=struct.unpack('I',train_len)[0]
        total=0
        while total<content_len:
            data=self.client_socket.recv(content_len-total)
            data_len=len(data)
            file.write(data)
            total+=data_len
        file.close()

    def deal_command(self,client_socket,client_addr):
        while True:
            command=self.recv_train(client_socket)
            if command[:2]=='ls':
                self.do_ls()
            elif command[:3]=='pwd':
                self.do_pwd()
            elif command[:2]=='cd':
                self.do_cd(command)
            elif command[:4]=='gets':
                self.do_gets(command)
            elif command[:4]=='puts':
                self.do_puts(command)
            elif command[:5]=='close':
                print(client_addr, "已断开连接！")
                break
            else:
                self.send_train('你输入了错误的命令!',False)

if __name__ == '__main__':
    s=Server('192.168.0.109',3000)
    s.tcp_init()
    po=Pool(3)
    while True:
        client_socket, client_addr = s.server_socket.accept()
        s.client_socket = client_socket
        print(client_addr, "已连接！")
        po.apply_async(s.deal_command, (client_socket,client_addr))
    po.close()
    po.join()
    s.server_socket.close()